package com.yfbao.horizon.utils;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
public class ConcurrentUtils {


    private static final Cache<String, LockDto> LOCK_MAP = Caffeine.newBuilder().expireAfterWrite(30, TimeUnit.MINUTES).maximumSize(200).build();

    private static LockDto getLock(String lockName){
        return  LOCK_MAP.getIfPresent(lockName);
    }

    /**
     * 释放锁
     * @param lockName
     */
    public static void releaseLockAndNotifyAll(String lockName) {
        synchronized (LOCK_MAP) {
            LockDto locklock = (LockDto) LOCK_MAP.getIfPresent(lockName);
            if (locklock != null) {
                locklock.getCondition().signalAll();
                locklock.getLock().unlock();
                locklock.setInCache(true);
                if (locklock.getLock().getHoldCount() == 0) {
                    LOCK_MAP.invalidate(lockName);
                }
            }
        }
    }

    /**
     * 尝试获取锁
     * @param lockName
     * @return
     */
    public static boolean tryLock(String lockName){
        LockDto lockDto = LOCK_MAP.getIfPresent(lockName);
        if(lockDto ==null){
            synchronized (LOCK_MAP) {
                lockDto = (LockDto) LOCK_MAP.getIfPresent(lockName);
                if (lockDto == null) {
                    lockDto = new LockDto();
                    LOCK_MAP.put(lockName, lockDto);
                }
            }
        }
        int holdCount = lockDto.getLock().getHoldCount();
        if(holdCount>0){
            return false;
        }
        boolean locked = lockDto.getLock().tryLock();
        return locked;
    }

    /**
     * 自旋等待
     * @param lockName
     * @param timeout
     */
    public static void spinWait(String lockName,long timeout){
        LockDto lock = getLock(lockName);
        if(lock ==null){
            return;
        }
        long start = System.currentTimeMillis();
        while (!lock.isInCache() && ((System.currentTimeMillis()-start)<timeout)) {
            // 自旋等待，条件未满足时不停地检查
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 条件满足后执行相应操作
    }


    @Data
    public static class LockDto {
        private ReentrantLock lock= new ReentrantLock();
        private Condition condition = lock.newCondition();
        private volatile boolean inCache =false;
    }

}
